#include "rrplane.h"
#include "rrtracer.h"
#include <cstdio>

RRPlane::RRPlane(RRTracer *arg)
{
    parent = arg;
    type = RR_PLANE;
}

float RRPlane::rrHit(RRRay arg)
{
    float denomi;
    RRVec3 d = arg.rrGetDir();
    RRVec3 r = arg.rrGetSrc();
    denomi = size.x * d.x + size.y * d.y + size.z * d.z;
    if(denomi == 0)
        return -1.0f;
    else {
        float numera;
        numera = size.x * (coord.x - r.x) + size.y * (coord.y - r.y) + size.z * (coord.z - r.z);
        float t;
        t = numera / denomi;
        //printf("%f\n", t);
        if(t <= 1.0e-4)
            return -1.0f;
        else {
            RRVec3 v1;
            v1 = RRSetVec3(r.x + t * d.x, r.y + t * d.y, r.z + t * d.z);
            tosrc = RRSetVec3(-t * d.x, -t * d.y, -t * d.z);
            tosrc = RRNormalize(tosrc);
            cross = v1;
            return RRDistance(r, v1);
        }
    }
}

RRVec4 RRPlane::rrCalcShadow(RRRay arg)
{
    RRLight l;
    l = parent->rrGetLight();
    RRVec3 l_c = l.rrGetCoord();
    float d_l;
    d_l = RRDistance(cross, l_c);

    RRPrim *p;
    float d, dmin;
    int it, index;
    dmin = 1.0e+18;
    it = primset->rrBegin();
    index = -1;
    while(it != primset->rrEnd()) {
        p = primset->rrGetPrim(it);
        d = p->rrHit(arg);
        //printf("distance:%f\n", d);
        if(d < dmin && d > 0.0f) {
            dmin = d;
            index = it;
        }
        it++;
    }

    if(index != -1) {
        if(dmin >= d_l)
            return RRSetVec4(1.0f, 1.0f, 1.0f, 1.0f);
        else
            return RRSetVec4(0.0f, 0.0f, 0.0f, 1.0f);
    }
    return RRSetVec4(1.0f, 1.0f, 1.0f, 1.0f);
}

RRVec4 RRPlane::rrCalcGlare(RRVec3 N)
{
    float D;
    D = 2 * RRInnerProduct(tosrc, N);
    RRVec3 R;
    R = RRSetVec3(D * N.x - tosrc.x, D * N.y - tosrc.y, D * N.z - tosrc.z);
    RRRay r;
    r.rrSetSrc(cross);
    r.rrSetDir(R);

    RRPrim *p;
    float d, dmin;
    int it, index;
    dmin = 1.0e+10;
    it = primset->rrBegin();
    index = -1;
    while(it != primset->rrEnd()) {
        p = primset->rrGetPrim(it);
        d = p->rrHit(r);
        //printf("distance:%f\n", d);
        if(d < dmin && d > 0.0f) {
            dmin = d;
            index = it;
        }
        it++;
    }

    if(index != -1) {
        RRVec4 c;
        p = primset->rrGetPrim(index);
        c = p->rrTrace();
        return c;
    }
    else
        return RRSetVec4(0.0f, 0.0f, 0.0f, -1.0f);
}

RRVec4 RRPlane::rrTrace()
{
    RRLight l;
    l = parent->rrGetLight();
    RRVec3 l_c = l.rrGetCoord();
    RRVec3 L;
    L = RRSetVec3(l_c.x - cross.x, l_c.y - cross.y, l_c.z - cross.z);
    L = RRNormalize(L);

    RRRay r;
    r.rrSetSrc(cross);
    r.rrSetDir(L);

    RRVec4 sh = RRSetVec4(1.0f, 1.0f, 1.0f, 1.0f);
    sh = rrCalcShadow(r);

    RRVec3 N;
    N = RRNormalize(size);

    RRVec4 gl;
    if(reflection == true) {
            gl = rrCalcGlare(N);
            return gl;
    }

    float D;
    D = RRInnerProduct(N, L);
    D = (float)reversal * D;
    if(D < 0.0f) D = 0.0f;
    //printf("%f\n", diff.z);
    float w_temp = diff.w + sh.w;
    float r_temp, g_temp, b_temp;
    r_temp = (diff.x * D * diff.w + sh.x * sh.w) / w_temp;
    g_temp = (diff.y * D * diff.w + sh.y * sh.w) / w_temp;
    b_temp = (diff.z * D * diff.w + sh.z * sh.w) / w_temp;
    return RRSetVec4(r_temp, g_temp, b_temp, 1.0f);
}
